package com.mycloud.core.dao;

import com.mycloud.core.model.Identifiable;
import org.hibernate.ObjectNotFoundException;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.support.JpaDaoSupport;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import java.util.List;
import java.util.Map;

/**
 * User: hossein bahramian
 * Date: Sep 27, 2011
 * Time: 8:51:22 PM
 */
public class HibernateGenericDao extends JpaDaoSupport
        implements GenericDao {

    @Override
    public void persist(final Identifiable entity) {
        getJpaTemplate().execute(new JpaCallback<Long>(){
            @Override
            public Long doInJpa(EntityManager em) throws PersistenceException {
                em.persist(entity);
                return entity.getId();
            }

        });

    }


    @Override
    public <T> T get(Class<T> clazz, Long key) throws ObjectNotFoundException {
        T entity = getJpaTemplate().find(clazz, key);
        if(entity != null){
            return entity;
        }
        throw new ObjectNotFoundException(key, clazz.getName());
    }



    @Override
//    @Transactional
    public void delete(Object entity) {
        getJpaTemplate().remove(entity);
    }


    @Override
//    @Transactional
    public Integer executeUpdate(final String nativeQuery) {
        return executeUpdate(nativeQuery, null);
    }

    @Override
//    @Transactional
    public Integer executeUpdate(final String nativeQuery, final Map<String, Object> params) {
        return getJpaTemplate().execute(new JpaCallback<Integer>(){
            @Override
            public Integer doInJpa(EntityManager em) throws PersistenceException {
                final Query query = em.createNativeQuery(nativeQuery);
                if(params != null){
                    for(String key : params.keySet()){
                        final Object value = params.get(key);
                        query.setParameter(key, value);
                    }
                }
                return query.executeUpdate();
            }
        });
    }

    @Override
    public List<Object[]> executeFind(final String nativeQuery) {
        return getJpaTemplate().executeFind(new JpaCallback<List<Object[]>>(){
            @Override
            public List<Object[]> doInJpa(EntityManager em) throws PersistenceException {
                return em.createNativeQuery(nativeQuery).getResultList();
            }
        });
    }

    @Override
    public <T> T readByName(final Class<T> clazz, final String name) {
        return getJpaTemplate().execute(new JpaCallback<T>(){
            @Override
            public T doInJpa(EntityManager em) throws PersistenceException {
                return (T)em.createQuery("from " + clazz.getName() +
                        " where name = :name")
                        .setParameter("name", name).getSingleResult();
            }
        });
    }

    @Override
    public <T> Long readIdByName(final Class<T> clazz, final String name) {
        return getJpaTemplate().execute(new JpaCallback<Long>(){
            @Override
            public Long doInJpa(EntityManager em) throws PersistenceException {
                return Long.valueOf(String.valueOf(em.createQuery("select id from " + clazz.getName() +
                        " where name = :name")
                        .setParameter("name", name).getSingleResult()));
            }
        });
    }

}
